#include <iostream>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <cstring>
#include <cstdio>
using namespace std;

int main()
{
    key_t key = ftok(".",13);
    if(key == -1) {
        perror("ftok");
        return 1;
    }
    // 使用 IPC_CREAT，如果段已存在则直接打开，避免因 IPC_EXCL 失败
    int shmid = shmget(key, 1024, 0666|IPC_CREAT);
    if(shmid == -1) {
        perror("shmget");
        return 1;
    }
    pid_t pid = fork();
    if(pid == -1) {
        perror("fork");
        return 1;
    }
    if(pid == 0)
    {
        //子进程
        //从共享内存读取数据
        char* str = (char*)shmat(shmid, nullptr, SHM_RDONLY);
        if(str == (char*)-1) {
            perror("shmat");
            return 1;
        }
        while(true)
        {
            if(strcmp(str, "exit") == 0)
                break;
            printf("Child read: %s\n", str);
            sleep(1);
        }
        // 子进程分离共享内存
        if(shmdt(str) == -1) {
            perror("shmdt(child)");
        }
        exit(0);
    }
    //父进程
    //写数据到共享内存
    char* str = (char*)shmat(shmid, nullptr, 0);
    if(str == (char*)-1) {
        perror("shmat");
        return 1;
    }
    int cnt = 5;
    while(cnt--)
    {
        snprintf(str, 1024, "Hello child! I am a father process cnt:%d", 5 - cnt);
        sleep(1);
    }
    snprintf(str, 1024, "exit");
    int ret = waitpid(pid, nullptr, 0);
    if(ret == -1) {
        perror("waitpid");
        return 1;
    }
    // 父进程分离并删除共享内存段
    if(shmdt(str) == -1) {
        perror("shmdt(parent)");
    }
    if(shmctl(shmid, IPC_RMID, nullptr) == -1) {
        perror("shmctl(IPC_RMID)");
    }
    return 0;
}